package com.yykj.prescription.server.service.impl;

import com.google.common.base.Joiner;
import com.google.common.reflect.TypeToken;
import com.yykj.base.client.dto.WordBriefInfo;
import com.yykj.base.client.feign.BaseFeignClient;
import com.yykj.common.enums.ResultEnums;
import com.yykj.common.exception.NormalException;
import com.yykj.common.service.RedisService;
import com.yykj.common.util.GsonUtil;
import com.yykj.common.util.LocalDateTimeFormatterUtil;
import com.yykj.common.util.LocalStringUtil;
import com.yykj.common.util.PageRequestUtil;
import com.yykj.common.vo.PageData;
import com.yykj.drup.client.feign.DrupServerFeign;
import com.yykj.drup.client.form.DoctorProductFrom;
import com.yykj.message.center.client.dto.PrescriptionMessageBodyDTO;
import com.yykj.message.center.client.feign.MessageFeignClient;
import com.yykj.prescription.client.dto.*;
import com.yykj.prescription.client.enums.PrescriptionType;
import com.yykj.prescription.server.converter.PrescriptionDrugChinaDTOConverter;
import com.yykj.prescription.server.converter.PrescriptionDrugWestDTOConverter;
import com.yykj.prescription.server.converter.PrescriptionMemberDTOConverter;
import com.yykj.prescription.server.dto.prescription.PrescriptionListSearchDTO;
import com.yykj.prescription.server.model.entity.prescription.*;
import com.yykj.prescription.server.model.entity.setting.PrescriptionCheckMember;
import com.yykj.prescription.server.model.entity.setting.PrescriptionSetting;
import com.yykj.prescription.server.model.repository.prescription.*;
import com.yykj.prescription.server.service.PrescriptionService;
import com.yykj.prescription.server.service.PrescriptionSettingService;
import com.yykj.prescription.server.service.TemplateService;
import com.yykj.prescription.server.vo.BackPrescriptionListVO;
import com.yykj.prescription.server.vo.PrescriptionListVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.pulsar.client.api.PulsarClientException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@Transactional
@Slf4j
public class PrescriptionServiceImpl implements PrescriptionService {
    @Override
    public Prescription createPrescription(PrescriptionCreateDTO createDTO) {
        if (createDTO.getDoctorInfo() == null || createDTO.getDoctorInfo().getHospitalId() == null
                || StringUtils.isEmpty(createDTO.getDoctorInfo().getDoctorId())
                || createDTO.getType() == null || createDTO.getOrigin() == null) {
            throw new NormalException(ResultEnums.PARAM_ERROR);
        }
        Integer hospitalId = createDTO.getDoctorInfo().getHospitalId();
        //处方基本信息
        Prescription prescription = new Prescription();

        BeanUtils.copyProperties(createDTO, prescription);
        BeanUtils.copyProperties(createDTO.getDoctorInfo(), prescription);
        BeanUtils.copyProperties(createDTO.getPatientInfo(), prescription);

        String prescriptionId = generatePrescriptionId(createDTO);
        prescription.setPrescriptionId(prescriptionId);
        //患者拼音生成
        String patientName = StringUtils.trimAllWhitespace(prescription.getPatientName());
        if (!StringUtils.isEmpty(patientName)) {
            String[] split = patientName.split("");
            StringBuilder sb = new StringBuilder();
            try {
                for (String s : split) {
                    WordBriefInfo wordBriefInfo = baseFeignClient.getWordBriefInfo(s);
                    if (!StringUtils.isEmpty(wordBriefInfo.getPy())) {
                        sb.append(wordBriefInfo.getPy().charAt(0));
                    }
                }
            } catch (Exception e) {
                log.info("获取拼音失败");
            }
            prescription.setPatientNamePy(sb.toString());
        }

        //处方基本设置检查
        PrescriptionSetting setting = settingService.getPrescriptionSetting(hospitalId);
        BeanUtils.copyProperties(setting, prescription);
        prescription.setStatus(1);

        Set<Integer> drugIds = new HashSet<>();
        // 处方药品入库
        if (PrescriptionType.china.equals(prescription.getType())) {//中药处方
            PrescriptionDrugChinaInfo info = new PrescriptionDrugChinaInfo();
            BeanUtils.copyProperties(createDTO.getChinaUseInfo(),info);
            info.setPrescriptionId(prescription.getPrescriptionId());
            chinaInfoRepository.save(info);
            List<PrescriptionDrugChina> chinaList = new ArrayList<>();
            for (PrescriptionDrugChinaDTO drug : createDTO.getChinaDrugList()) {
                PrescriptionDrugChina chinaDrug = new PrescriptionDrugChina();
                BeanUtils.copyProperties(drug,chinaDrug);
                drugIds.add(Integer.parseInt(drug.getDrugId()));
                chinaDrug.setPrescriptionId(prescription.getPrescriptionId());
                chinaList.add(chinaDrug);
            }
            chinaRepository.saveAll(chinaList);
        } else {
            List<PrescriptionDrugWest> westList = new ArrayList<>();
            for (PrescriptionDrugWestDTO drug : createDTO.getWestDrugList()) {
                PrescriptionDrugWest westDrug = new PrescriptionDrugWest();
                BeanUtils.copyProperties(drug,westDrug);
                drugIds.add(Integer.parseInt(drug.getDrugId()));
                westDrug.setPrescriptionId(prescription.getPrescriptionId());
                westList.add(westDrug);
            }
            westRepository.saveAll(westList);
        }

        List<Integer> drugIdList = new ArrayList<>(drugIds);
        Collections.sort(drugIdList);
        String join = Joiner.on(",").join(drugIdList);
        join = "," + join + ",";
        prescription.setDrugIds(join);

        prescription = prescriptionRepository.save(prescription);
        templateService.increaseUseCnt(createDTO.getDoctorInfo().getDoctorId(), createDTO.getTempIds());

        //处方人员配置
        List<PrescriptionCheckMember> memberList = settingService.listPrescriptionCheckMember(hospitalId);
        List<PrescriptionMember> prescriptionMemberList = getPrescriptionMember(hospitalId, memberList, setting.getChangeMemberCnt());
        List<PrescriptionMember> saveList = new ArrayList<>();
        PrescriptionMember creator = PrescriptionMember.builder()
                .prescriptionId(prescriptionId)
                .memberId(createDTO.getDoctorInfo().getDoctorId())
                .memberName(createDTO.getDoctorInfo().getDoctorName())
                .sign(createDTO.getDoctorInfo().getSign())
                .role(0)
                .headImg(createDTO.getDoctorInfo().getHeadImage())
                .build();
        saveList.add(creator);
        if (prescriptionMemberList.size() > 0) {
            for (PrescriptionMember member : prescriptionMemberList) {
                member.setPrescriptionId(prescriptionId);
                saveList.add(member);
            }
        }
        memberRepository.saveAll(saveList);

        DoctorProductFrom doctorProductFrom = new DoctorProductFrom();
        doctorProductFrom.setDoctorId(prescription.getDoctorId());
        Integer categoryType = 1;//1：西药 2：中药
        if(PrescriptionType.china.equals(prescription.getType())){
            categoryType = 2;
        }
        doctorProductFrom.setCategoryType(categoryType);
        doctorProductFrom.setProductIds(drugIdList);
        try {
            drupServerFeign.addOften(doctorProductFrom);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //处方任务添加
        if (!setting.getForever()) {//不是永久有效的，就要设置过期时间,且加入定时任务更新列表里
            prescription.setExpireTime(LocalDateTime.now().plusSeconds(setting.getEffectiveTime()));
            PrescriptionTask prescriptionTask = new PrescriptionTask();
            BeanUtils.copyProperties(prescription, prescriptionTask);
            taskRepository.save(prescriptionTask);
        }

        return prescription;
    }

    @Override
    public PageData<PrescriptionListVO> listPrescription(PrescriptionListSearchDTO searchDTO) {
        PageRequest pageRequest = PageRequest.of(PageRequestUtil.getPage(searchDTO.getCurrentPage())
                , PageRequestUtil.getSize(searchDTO.getPageSize()), Sort.by(Sort.Order.desc("addTime")));
        Page<Prescription> list = prescriptionRepository.findAll(generateSpecification(searchDTO), pageRequest);
        PageData<PrescriptionListVO> ret = new PageData<>();
        ret.setTotalPage(list.getTotalPages());
        ret.setTotalCount(list.getTotalElements());
        ret.setCurrentPage(PageRequestUtil.getPage(searchDTO.getCurrentPage()) + 1);
        ret.setPageSize(PageRequestUtil.getSize(searchDTO.getPageSize()));
        List<PrescriptionListVO> voList = new ArrayList<>();
        for (Prescription prescription : list) {
            PrescriptionListVO vo = new PrescriptionListVO();
            BeanUtils.copyProperties(prescription, vo);
            voList.add(vo);
        }
        ret.setList(voList);
        return ret;
    }

    @Override
    public PageData<BackPrescriptionListVO> listBackPrescription(PrescriptionListSearchDTO searchDTO) {
        PageData<BackPrescriptionListVO> result = new PageData<>();
        PageData<PrescriptionListVO> prescriptionListVOPageData = listPrescription(searchDTO);
        BeanUtils.copyProperties(prescriptionListVOPageData, result);
        List<String> prescriptionIds = new ArrayList<>();
        List<BackPrescriptionListVO> list = new ArrayList<>();
        for (PrescriptionListVO listVO : prescriptionListVOPageData.getList()) {
            prescriptionIds.add(listVO.getPrescriptionId());
            BackPrescriptionListVO vo = new BackPrescriptionListVO();
            BeanUtils.copyProperties(listVO, vo);
            list.add(vo);
        }
        result.setList(list);
        List<PrescriptionDrugChina> chinaList = chinaRepository.findAllByPrescriptionIdIn(prescriptionIds);
        List<PrescriptionDrugChinaInfo> infoList = chinaInfoRepository.findAllByPrescriptionIdIn(prescriptionIds);
        List<PrescriptionDrugWest> westList = westRepository.findAllByPrescriptionIdIn(prescriptionIds);
        for (BackPrescriptionListVO vo : result.getList()) {
            if (PrescriptionType.china.equals(vo.getType())) {
                for (PrescriptionDrugChina china : chinaList) {
                    if (vo.getPrescriptionId().equalsIgnoreCase(china.getPrescriptionId())) {
                        if (vo.getChinaDrugList() == null) {
                            vo.setChinaDrugList(new ArrayList<>());
                        }
                        vo.getChinaDrugList().add(PrescriptionDrugChinaDTOConverter.convert(china));
                    }
                }

                for (PrescriptionDrugChinaInfo info : infoList) {
                    if (vo.getPrescriptionId().equalsIgnoreCase(info.getPrescriptionId())) {
                        PrescriptionDrugChinaInfoDTO infoDTO = new PrescriptionDrugChinaInfoDTO();
                        BeanUtils.copyProperties(info,infoDTO);
                        vo.setChinaUseInfo(infoDTO);
                    }
                }
            } else {
                for (PrescriptionDrugWest west : westList) {
                    if (vo.getPrescriptionId().equalsIgnoreCase(west.getPrescriptionId())) {
                        if (vo.getWestDrugList() == null) {
                            vo.setWestDrugList(new ArrayList<>());
                        }
                        vo.getWestDrugList().add(PrescriptionDrugWestDTOConverter.convert(west));
                    }
                }
            }
        }

        return result;
    }

    @Override
    public PrescriptionDetailDTO prescriptionInfo(String prescriptionId) {
        Prescription prescription = prescriptionRepository.findById(prescriptionId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        PrescriptionDetailDTO detailDTO = new PrescriptionDetailDTO();
        BeanUtils.copyProperties(prescription, detailDTO);
        if (PrescriptionType.china.equals(prescription.getType())) {
            List<PrescriptionDrugChina> chinaList = chinaRepository.findAllByPrescriptionId(prescriptionId);
            detailDTO.setChinaDrugList(PrescriptionDrugChinaDTOConverter.convert(chinaList));
            PrescriptionDrugChinaInfo info = chinaInfoRepository.findById(prescriptionId).orElse(null);
            PrescriptionDrugChinaInfoDTO infoDTO = new PrescriptionDrugChinaInfoDTO();
            BeanUtils.copyProperties(info, infoDTO);
            detailDTO.setChinaUseInfo(infoDTO);

        } else {
            List<PrescriptionDrugWest> westList = westRepository.findAllByPrescriptionId(prescriptionId);
            detailDTO.setWestDrugList(PrescriptionDrugWestDTOConverter.convert(westList));
        }
        List<PrescriptionMember> memberList = memberRepository.findAllByPrescriptionId(prescriptionId);
        detailDTO.setMemberList(PrescriptionMemberDTOConverter.convert(memberList));

        return detailDTO;
    }

    @Override
    public void autoCheckPrescription(String prescriptionId) {
        Prescription prescription = prescriptionRepository.findById(prescriptionId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        PrescriptionSetting prescriptionSetting = settingService.getPrescriptionSetting(prescription.getHospitalId());
        if (prescriptionSetting.getCheckType() == 1) {
            prescription.setCheckTime(LocalDateTime.now());
            prescription.setStatus(2);
            prescriptionRepository.save(prescription);
            PrescriptionMessageBodyDTO messageBodyDTO = new PrescriptionMessageBodyDTO();
            BeanUtils.copyProperties(prescription, messageBodyDTO);
            try {
                messageFeignClient.sendPrescriptionChangeMessage(messageBodyDTO);
            } catch (PulsarClientException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void userCheckPrescription(PrescriptionCheckDTO checkDTO) {
        Prescription prescription = prescriptionRepository.findById(checkDTO.getPrescriptionId()).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));
        List<PrescriptionCheckMember> memberList = settingService.listPrescriptionCheckMember(prescription.getHospitalId());
        //审核角色,1:药师，2审方，3调配，4核对，5发药
        boolean flag = false;
        for (PrescriptionCheckMember member : memberList) {
            if (member.getMemberId().equalsIgnoreCase(checkDTO.getCheckerId())
                    && member.getRole().equals(1)) {
                flag = true;
            }
        }
        if (!flag) {
            throw new NormalException(ResultEnums.PRESCRIPTION_CHECK_ROLE_ERROR);
        }
        prescription.setStatus(checkDTO.getStatus());
        prescription.setCheckTime(LocalDateTime.now());
        if (checkDTO.getStatus() == 4) {
            prescription.setDisableTime(LocalDateTime.now());
        }
        prescriptionRepository.save(prescription);

        PrescriptionMessageBodyDTO bodyDTO = new PrescriptionMessageBodyDTO();
        BeanUtils.copyProperties(prescription, bodyDTO);
        try {
            messageFeignClient.sendPrescriptionChangeMessage(bodyDTO);
        } catch (PulsarClientException e) {
            e.printStackTrace();
        }

    }

    @Override
    public PrescriptionOrderCheckResultDTO checkPrescriptionOrder(String prescriptionId) {
        PrescriptionOrderCheckResultDTO resultDTO = new PrescriptionOrderCheckResultDTO();
        resultDTO.setPrescriptionId(prescriptionId);
        resultDTO.setAvailable(false);
        Prescription prescription = prescriptionRepository.findById(prescriptionId).orElseThrow(() -> new NormalException(ResultEnums.NOT_EXIST));

        if(prescription.getStatus() == 5 && prescription.getTransAvailable() !=null && !prescription.getTransAvailable()){
            resultDTO.setMessage("该处方流转后不可用");
            return resultDTO;
        }
        if(prescription.getStatus() != 2){
            //1未审核，2已审核，3已失效，4作废,5已流转
            if(prescription.getStatus() == 1){
                resultDTO.setMessage("该处方未审核通过");
            }
            if(prescription.getStatus() == 3){
                resultDTO.setMessage("该处方已失效");
            }
            if(prescription.getStatus() == 4){
                resultDTO.setMessage("该处方已作废");
            }
            return resultDTO;
        }else{
            if(prescription.getEndless()!=null && !prescription.getEndless() && prescription.getCnt()<=0){
                resultDTO.setMessage("处方已经达到最大使用次数");
                return resultDTO;
            }
            if(prescription.getForever()!=null && !prescription.getForever() ){
                if(prescription.getExpireTime()!=null && prescription.getExpireTime().isBefore(LocalDateTime.now())){
                    resultDTO.setMessage("该处方已失效");
                    return resultDTO;
                }
            }
        }
        resultDTO.setAvailable(true);
        return resultDTO;
    }

    private Specification<Prescription> generateSpecification(PrescriptionListSearchDTO searchDTO) {
        return new Specification<Prescription>() {
            @Override
            public Predicate toPredicate(Root<Prescription> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                List<Predicate> predicateList = new ArrayList<>();
                if (searchDTO.getHospitalId() != null && searchDTO.getHospitalId() > 0) {
                    predicateList.add(builder.equal(root.get("hospitalId"), searchDTO.getHospitalId()));
                }
                if (!StringUtils.isEmpty(searchDTO.getDoctorId())) {
                    predicateList.add(builder.equal(root.get("doctorId"), searchDTO.getDoctorId()));
                }
                if (!StringUtils.isEmpty(searchDTO.getDoctorName())) {
                    predicateList.add(builder.like(root.get("doctorName"), LocalStringUtil.getLikeString(searchDTO.getDoctorName())));
                }
                if (!StringUtils.isEmpty(searchDTO.getUserId())) {
                    predicateList.add(builder.equal(root.get("userId"), searchDTO.getUserId()));
                }
                if (!StringUtils.isEmpty(searchDTO.getPatientId())) {
                    predicateList.add(builder.equal(root.get("patientId"), searchDTO.getPatientId()));
                }
                if (!StringUtils.isEmpty(searchDTO.getPatientName())) {
                    Predicate p1 = builder.equal(root.get("patientNamePy"), searchDTO.getPatientName());
                    Predicate p2 = builder.like(root.get("patientName"), LocalStringUtil.getLikeString(searchDTO.getPatientName()));
                    predicateList.add(builder.or(p1, p2));
                }
                if (searchDTO.getOrigin() != null && searchDTO.getOrigin() > 0) {
                    predicateList.add(builder.equal(root.get("origin"), searchDTO.getOrigin()));
                }
                if (searchDTO.getStatus() != null && searchDTO.getOrigin() > 0) {
                    predicateList.add(builder.equal(root.get("status"), searchDTO.getStatus()));
                }

                if (searchDTO.getType() != null) {
                    predicateList.add(builder.equal(root.get("type"), searchDTO.getType()));
                }
                if (!StringUtils.isEmpty(searchDTO.getStartTime())) {
                    LocalDateTime startTime = LocalDateTime.of(
                            LocalDate.parse(searchDTO.getStartTime(), LocalDateTimeFormatterUtil.getLocalDateFormatter()),
                            LocalTime.MIN);
                    predicateList.add(builder.greaterThanOrEqualTo(root.get("addTime"), startTime));
                }
                if (!StringUtils.isEmpty(searchDTO.getEndTime())) {
                    LocalDateTime endTime = LocalDateTime.of(
                            LocalDate.parse(searchDTO.getEndTime(), LocalDateTimeFormatterUtil.getLocalDateFormatter()),
                            LocalTime.MAX
                    );
                    predicateList.add(builder.lessThanOrEqualTo(root.get("addTime"), endTime));
                }

                if (!StringUtils.isEmpty(searchDTO.getDepName())) {
                    predicateList.add(builder.like(root.get("depName"), LocalStringUtil.getLikeString(searchDTO.getDepName())));
                }

                if(searchDTO.getDepId() !=null && searchDTO.getDepId() > 0){
                    predicateList.add(builder.equal(root.get("depId"), searchDTO.getDepId()));
                }

                if (!StringUtils.isEmpty(searchDTO.getDrugIds())) {
                    String[] split = searchDTO.getDrugIds().split(",");
                    for (String s : split) {
                        String s1 = StringUtils.trimAllWhitespace(s);
                        predicateList.add(builder.like(root.get("drugIds"), "%," + s1 + ",%"));
                    }
                }

                Predicate[] predicates = new Predicate[predicateList.size()];
                return query.where(predicateList.toArray(predicates)).getRestriction();
            }
        };
    }

    private List<PrescriptionMember> getPrescriptionMember(Integer hospitalId, List<PrescriptionCheckMember> memberList, Integer changeMemberCnt) {
        Map<Integer, List<PrescriptionMember>> map = new HashMap<>();
        List<PrescriptionMember> result = new ArrayList<>();
        if (memberList.size() > 0) {
            for (PrescriptionCheckMember prescriptionCheckMember : memberList) {
                if (prescriptionCheckMember.getStatus()) {
                    PrescriptionMember member = new PrescriptionMember();
                    BeanUtils.copyProperties(prescriptionCheckMember, member);
                    List<PrescriptionMember> tempList = map.getOrDefault(member.getRole(), new ArrayList<>());
                    member.setId(null);
                    tempList.add(member);
                    map.put(member.getRole(), tempList);
                }

            }
        }
        String cntKey = "prescription_change_member_cnt_" + hospitalId;
        String dataKey = "prescription_change_data" + hospitalId;
        String val = redisService.get(cntKey);
        int cnt = 0;
        if (val != null) {
            cnt = Integer.parseInt(val);
        }
        if (cnt < changeMemberCnt) {
            String s = redisService.get(dataKey);
            if (s != null) {
                result = GsonUtil.fromJson(s, new TypeToken<List<PrescriptionMember>>() {
                }.getType());
            } else {
                for (Integer i : map.keySet()) {
                    List<PrescriptionMember> prescriptionMemberList = map.get(i);
                    if (prescriptionMemberList != null && prescriptionMemberList.size() > 0) {
                        result.add(prescriptionMemberList.get(0));
                    }
                }
            }
        } else {
            PrescriptionStatistic statistic = statisticRepository.findById(LocalDate.now()).orElse(null);
            if (statistic == null) {
                statistic = new PrescriptionStatistic();
                statistic.setDay(LocalDate.now());
            }

            for (int i = 1; i <= 5; i++) {
                List<PrescriptionMember> list = map.get(i);
                if (list != null && list.size() > 0) {
                    Integer index = 0;
                    switch (i) {
                        case 1:
                            index = statistic.getRole1();
                            break;
                        case 2:
                            index = statistic.getRole2();
                            break;
                        case 3:
                            index = statistic.getRole3();
                            break;
                        case 4:
                            index = statistic.getRole4();
                            break;
                        case 5:
                            index = statistic.getRole5();
                            break;
                        default:
                            break;
                    }
                    if(index == null){
                        index = 0;
                    }
                    if (index < list.size() - 1) {
                        index++;
                    } else {
                        index = 0;
                    }
                    switch (i) {
                        case 1:
                            statistic.setRole1(index);
                            break;
                        case 2:
                            statistic.setRole2(index);
                            break;
                        case 3:
                            statistic.setRole3(index);
                            break;
                        case 4:
                            statistic.setRole4(index);
                            break;
                        case 5:
                            statistic.setRole5(index);
                            break;

                        default:
                            break;
                    }
                    result.add(list.get(index));
                }
            }
            cnt = 0;
            statisticRepository.save(statistic);
        }
        cnt++;
        redisService.set(cntKey, "" + cnt);
        redisService.set(dataKey, GsonUtil.toJson(result));
        return result;
    }

    public String generatePrescriptionId(PrescriptionCreateDTO createDTO) {
        String prefix = "X";
        if (PrescriptionType.china.equals(createDTO.getType())) {
            prefix = "Z";
        }
        return String.format("%s%03d%s%06d", prefix, createDTO.getOrigin(),
                LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")), getNextIndex());

    }

    private Integer getNextIndex() {
        String lockValue;
        boolean lockStatus;
        int cnt = 0;
        do {
            cnt++;
            lockValue = "" + (System.currentTimeMillis() + 2000);
            lockStatus = redisService.lock("prescription_key_lock", lockValue);
            if (!lockStatus) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        } while (cnt < 5 && !lockStatus);
        if (!lockStatus) {
            throw new NormalException(ResultEnums.REDIS_LOCK_ERROR);
        }

        String prescriptionKey = redisService.get("prescription_key");
        int key;
        PrescriptionStatistic statistic = statisticRepository.findById(LocalDate.now()).orElse(null);
        if (prescriptionKey == null) {
            if (statistic == null) {
                key = 0;
            } else {
                key = statistic.getCnt();
            }
        } else {
            key = Integer.parseInt(prescriptionKey);
        }
        key++;
        if (statistic == null) {
            statistic = new PrescriptionStatistic();
        }
        statistic.setDay(LocalDate.now());
        statistic.setCnt(key);
        statisticRepository.save(statistic);
        redisService.set("prescription_key", "" + key);
        redisService.unlock("prescription_key_lock", lockValue);
        return key;
    }

    private RedisService redisService;

    private PrescriptionStatisticRepository statisticRepository;

    private PrescriptionRepository prescriptionRepository;

    private PrescriptionDrugChinaInfoRepository chinaInfoRepository;

    private PrescriptionDrugChinaRepository chinaRepository;

    private PrescriptionDrugWestRepository westRepository;

    private TemplateService templateService;

    private PrescriptionSettingService settingService;

    private PrescriptionMemberRepository memberRepository;

    private BaseFeignClient baseFeignClient;

    private MessageFeignClient messageFeignClient;

    private PrescriptionTaskRepository taskRepository;

    private DrupServerFeign drupServerFeign;

    @Autowired
    public void setPrescriptionRepository(PrescriptionRepository prescriptionRepository) {
        this.prescriptionRepository = prescriptionRepository;
    }

    @Autowired
    public void setChinaInfoRepository(PrescriptionDrugChinaInfoRepository chinaInfoRepository) {
        this.chinaInfoRepository = chinaInfoRepository;
    }

    @Autowired
    public void setChinaRepository(PrescriptionDrugChinaRepository chinaRepository) {
        this.chinaRepository = chinaRepository;
    }

    @Autowired
    public void setWestRepository(PrescriptionDrugWestRepository westRepository) {
        this.westRepository = westRepository;
    }

    @Autowired
    public void setTemplateService(TemplateService templateService) {
        this.templateService = templateService;
    }

    @Autowired
    public void setStatisticRepository(PrescriptionStatisticRepository statisticRepository) {
        this.statisticRepository = statisticRepository;
    }

    @Autowired
    public void setRedisService(RedisService redisService) {
        this.redisService = redisService;
    }

    @Autowired
    public void setSettingService(PrescriptionSettingService settingService) {
        this.settingService = settingService;
    }

    @Autowired
    public void setMemberRepository(PrescriptionMemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Autowired
    public void setBaseFeignClient(BaseFeignClient baseFeignClient) {
        this.baseFeignClient = baseFeignClient;
    }

    @Autowired
    public void setMessageFeignClient(MessageFeignClient messageFeignClient) {
        this.messageFeignClient = messageFeignClient;
    }

    @Autowired
    public void setTaskRepository(PrescriptionTaskRepository taskRepository) {
        this.taskRepository = taskRepository;
    }

    @Autowired
    public void setDrupServerFeign(DrupServerFeign drupServerFeign) {
        this.drupServerFeign = drupServerFeign;
    }
}
